#![cfg_attr(debug_assertions, allow(dead_code, unused_imports, unused_variables))]
use super::TypeSchema;
use super::{SymbolicTask, NominalTask, ProtocolError};
use nom::{
    branch::alt,
    bytes::complete::{tag, take_until},
    character::complete::{alpha1, alphanumeric1, char, multispace0},
    combinator::{map, opt, recognize},
    multi::{many0, separated_list0},
    sequence::{delimited, pair, preceded, separated_pair, terminated},
    IResult, Parser,
};

impl SymbolicTask {
    pub fn try_parse(signature: &NominalTask) -> Result<Self, ProtocolError> {
        task_nominal_to_symbolic(signature)
    }

    pub fn parse(task: &NominalTask) -> Self {
        match SymbolicTask::try_parse(task) {
            Ok(task) => task,
            Err(e) => panic!("Failed to parse task schema: {}", task),
        }
    }
}

impl TypeSchema {
    pub fn try_parse(input: &str) -> Result<Self, ProtocolError> {
        parse_abs_type(input)
    }
    pub fn parse(input: &str) -> Self {
        match TypeSchema::try_parse(input) {
            Ok(task) => task,
            Err(e) => panic!("Failed to parse typeschema: {}", input),
        }
    }
    pub fn try_parse_short(input: &str) -> Result<Self, ProtocolError> {
        parse_abs_type_short(input)
    }
    pub fn parse_short(input: &str) -> Self {
        match TypeSchema::try_parse_short(input) {
            Ok(task) => task,
            Err(e) => panic!("Failed to parse typeschema: {}", input),
        }
    }
}

pub fn task_nominal_to_symbolic(task: &NominalTask) -> Result<SymbolicTask, ProtocolError> {
    let mut splits = task.split(':');
    if let (Some(name), Some(tpe), None) = (splits.next(), splits.next(), splits.next()) {
        let mut splits2 = tpe.split("->");
        if let (Some(tin), Some(tout), None) = (splits2.next(), splits2.next(), splits2.next()) {
            let stin = parse_tpe(tin)?;
            let stout = parse_tpe(tout)?;
            return Ok(SymbolicTask::new(name.into(), stin, stout))
        }
        else {
            return Err(ProtocolError::TaskSignatureParseError(format!("任务签名不能正确分割箭头: {}", task)));
        }
    }
    Err(ProtocolError::TaskSignatureParseError(format!("任务签名不能正确分割冒号: {}", task)))
}

fn parse_tpe(tpe: &str) -> Result<TypeSchema, ProtocolError> {
    entry(tpe).map(|x|x.1).map_err(|_|ProtocolError::TypeSchemaParseError(format!("类型解析错误: {}", tpe)))
}

fn basic_type(input: &str) -> IResult<&str, TypeSchema> {
    alt((
        tag("Void").map(|_| TypeSchema::Void),
        tag("Int").map(|_| TypeSchema::Int),
        tag("Float").map(|_| TypeSchema::Float),
        tag("Str").map(|_| TypeSchema::Str),
        tag("Bool").map(|_| TypeSchema::Bool),
        tag("Json").map(|_| TypeSchema::Json),
    )).parse(input)
}

fn list_type(i: &str) -> IResult<&str, TypeSchema> {
    let (i, _) = tag("List<")(i)?;
    let (i, t) = entry(i)?;
    let (i, _) = tag(">")(i)?;
    Ok((i, TypeSchema::List(Box::new(t))))
}

fn map_type(i: &str) -> IResult<&str, TypeSchema> {
    let (i, _) = tag("Map<")(i)?;
    let (i, k) = entry(i)?;
    let (i, _) = tag(",")(i)?;
    let (i, v) = entry(i)?;
    let (i, _) = tag(">")(i)?;
    Ok((i, TypeSchema::Map(Box::new(k), Box::new(v))))
}

fn option_type_alt(i: &str) -> IResult<&str, TypeSchema> {
    let (i, _) = tag("Option<")(i)?;
    let (i, t) = entry(i)?;
    let (i, _) = tag(">")(i)?;
    Ok((i, TypeSchema::Opt(Box::new(t))))
}

fn option_type(i: &str) -> IResult<&str, TypeSchema> {
    let (i, _) = tag("?")(i)?;
    let (i, t) = entry(i)?;
    Ok((i, TypeSchema::Opt(Box::new(t))))
}

fn tuple_type(input: &str) -> IResult<&str, TypeSchema> {
    map(
        delimited(
            char('('),
            separated_list0(
                tag(","),
                entry
            ),
            char(')')
        ),
        |types| TypeSchema::Tuple(types)
    ).parse(input)
}

macro_rules! nom_error {
    ($input:expr) => {
        Err(nom::Err::Error(nom::error::Error::new($input, nom::error::ErrorKind::Tag)))
    };
}

fn ident(i: &str) -> IResult<&str, &str> {
    recognize(pair(
        alpha1,
        many0(alt((alphanumeric1, tag("_"))))
    )).parse(i)
}

fn custom_type(i: &str) -> IResult<&str, TypeSchema> {
    let (ii, name) = ident(i)?;
    match name {
        "List" | "Map" | "Tuple" | "Option" => nom_error!(i), // 自定义类型不能是List, Map, Tuple, Option
        _ => Ok((ii, TypeSchema::DataType(name.into())))
    }
}

fn entry(input: &str) -> IResult<&str, TypeSchema> {
    alt((
        basic_type,
        list_type,
        map_type,
        tuple_type,
        option_type,
        option_type_alt,
        custom_type
    )).parse(input)
}

pub fn parse_abs_type(input: &str) -> Result<TypeSchema, ProtocolError> {
    let input = input.replace(" ", "");
    entry(&input).map(|x|x.1).map_err(|_|ProtocolError::TypeSchemaParseError(format!("类型解析错误: {}", input)))
}

fn list_type_short(i: &str) -> IResult<&str, TypeSchema> {
    let (i, _) = tag("[")(i)?;
    let (i, t) = entry_short(i)?;
    let (i, _) = tag("]")(i)?;
    Ok((i, TypeSchema::List(Box::new(t))))
}

fn map_type_short(i: &str) -> IResult<&str, TypeSchema> {
    let (i, _) = tag("{}")(i)?;
    let (i, k) = entry_short(i)?;
    let (i, _) = tag(",")(i)?;
    let (i, v) = entry_short(i)?;
    let (i, _) = tag("}")(i)?;
    Ok((i, TypeSchema::Map(Box::new(k), Box::new(v))))
}

fn tuple_type_short(i: &str) -> IResult<&str, TypeSchema> {
    map(
        delimited(
            char('('),
            separated_list0(tag(","), entry_short),
            char(')')
        ),
        |types| TypeSchema::Tuple(types)
    ).parse(i)
}

fn option_type_short(i: &str) -> IResult<&str, TypeSchema> {
    let (i, _) = tag("?")(i)?;
    let (i, t) = entry_short(i)?;
    Ok((i, TypeSchema::Opt(Box::new(t))))
}

fn entry_short(input: &str) -> IResult<&str, TypeSchema> {
    alt((
        basic_type,
        list_type_short,
        map_type_short,
        tuple_type_short,
        option_type_short,
        custom_type
    )).parse(input)
}
pub fn parse_abs_type_short(input: &str) -> Result<TypeSchema, ProtocolError> {
    let input = input.replace(" ", "");
    entry_short(&input).map(|x|x.1).map_err(|_|ProtocolError::TypeSchemaParseError(format!("类型解析错误: {}", input)))
}

fn list_type_1(i: &str) -> IResult<&str, TypeSchema> {
    let (i, _) = tag("List<")(i)?;
    let (i, t) = entry_both(i)?;
    let (i, _) = tag(">")(i)?;
    Ok((i, TypeSchema::List(Box::new(t))))
}

fn list_type_2(i: &str) -> IResult<&str, TypeSchema> {
    let (i, _) = tag("[")(i)?;
    let (i, t) = entry_both(i)?;
    let (i, _) = tag("]")(i)?;
    Ok((i, TypeSchema::List(Box::new(t))))
}

fn map_type_1(i: &str) -> IResult<&str, TypeSchema> {
    let (i, _) = tag("Map<")(i)?;
    let (i, k) = entry_both(i)?;
    let (i, _) = tag(",")(i)?;
    let (i, v) = entry_both(i)?;
    let (i, _) = tag(">")(i)?;
    Ok((i, TypeSchema::Map(Box::new(k), Box::new(v))))
}

fn map_type_2(i: &str) -> IResult<&str, TypeSchema> {
    let (i, _) = tag("{}")(i)?;
    let (i, k) = entry_both(i)?;
    let (i, _) = tag(",")(i)?;
    let (i, v) = entry_both(i)?;
    let (i, _) = tag("}")(i)?;
    Ok((i, TypeSchema::Map(Box::new(k), Box::new(v))))
}

fn tuple_type_1(i: &str) -> IResult<&str, TypeSchema> {
    map(
        delimited(
            char('('),
            separated_list0(char(','), entry_both),
            char(')')
        ),
        |t| TypeSchema::Tuple(t)
    ).parse(i)
}
fn tuple_type_2(i: &str) -> IResult<&str, TypeSchema> {
    map(
        delimited(
            tag("Option<"),
            separated_list0(char(','), entry_both),
            char('>')
        ),
        |t| TypeSchema::Tuple(t)
    ).parse(i)
}

fn option_type_1(i: &str) -> IResult<&str, TypeSchema> {
    let (i, _) = tag("Option<")(i)?;
    let (i, t) = entry_both(i)?;
    let (i, _) = tag(">")(i)?;
    Ok((i, TypeSchema::Opt(Box::new(t))))
}

fn option_type_2(i: &str) -> IResult<&str, TypeSchema> {
    let (i, _) = tag("?")(i)?;
    let (i, t) = entry_both(i)?;
    Ok((i, TypeSchema::Opt(Box::new(t))))
}

fn entry_both(input: &str) -> IResult<&str, TypeSchema> {
    alt((
        basic_type,
        list_type_1,
        list_type_2,
        map_type_1,
        map_type_2,
        tuple_type_1,
        tuple_type_2,
        option_type_1,
        option_type_2,
        custom_type
    )).parse(input)
}

pub fn parse_abs_type_both(input: &str) -> Result<TypeSchema, ProtocolError> {
    let input = input.replace(" ", "");
    entry_both(&input).map(|x|x.1).map_err(|_|ProtocolError::TypeSchemaParseError(format!("类型解析错误: {}", input)))
}